﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace XP_More
{
	public partial class DuplicateForm : Form
	{
		private VmInfo m_srcVm;
		private string m_newVm = "";
		private bool m_isIdle = true;
		private Duplicator m_duplicator;

		// Initialize a duplicate form with the source VM descriptor
		public DuplicateForm(VmInfo srcVm)
		{
			m_srcVm = srcVm;

			InitializeComponent();
			FormBorderStyle = FormBorderStyle.FixedSingle;

			newVmcDir.Text = GetFileDir(srcVm.Vmc);
			newVhdDir.Text = GetFileDir(srcVm.Vhd);
		}

		// Get the name of the newly created VM
		public string NewVM { get { return m_newVm; } }

		private void vmcPathBtn_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog folderDialog = new FolderBrowserDialog();
			folderDialog.Description = "Select VMC folder";
			folderDialog.SelectedPath = newVmcDir.Text;
			if (folderDialog.ShowDialog() == DialogResult.OK)
			{
				newVmcDir.Text = folderDialog.SelectedPath;
				if (newVhdDir.Text == "")
					newVhdDir.Text = newVmcDir.Text;
			}
		}

		private void vhdPathBtn_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog folderDialog = new FolderBrowserDialog();
			folderDialog.Description = "Select VHD folder";
			folderDialog.SelectedPath = newVhdDir.Text;
			if (folderDialog.ShowDialog() == DialogResult.OK)
			{
				newVhdDir.Text = folderDialog.SelectedPath;
				if (newVmcDir.Text == "")
					newVmcDir.Text = newVhdDir.Text;
			}
		}

		private void dupBtn_Click(object sender, EventArgs e)
		{
			if (m_isIdle)
			{
				if (!ValidateParams())
					return;
				try
				{
					string vmcxFile = m_srcVm.Vmcx.Replace(m_srcVm.Name + ".vmcx",
						newVmName.Text + ".vmcx");
					string vmcFile = FullDir(newVmcDir.Text) + newVmName.Text + ".vmc";
					string vhdFile = FullDir(newVhdDir.Text) + newVmName.Text + ".vhd";
					string vsvFile = vmcFile.ToLower().Replace(".vmc", ".vsv");
					if (!File.Exists(m_srcVm.Vsv))
						vsvFile = "";
					VmInfo trgVm = new VmInfo(vmcxFile, m_srcVm.State, vmcFile, 
						vhdFile, vsvFile, m_srcVm.Comment);

					dupWorker.RunWorkerAsync(trgVm);
					m_isIdle = false;
					dupBtn.Text = "Cancel";
				}
				catch (Exception ex)
				{
					MessageBox.Show("Errr... the duplication has failed due to " +
						"unexpected circumstances.\n\nThe gory details:\n" +
						ex.Message);
					dupBtn.Text = "Duplicate!";
					dupBtn.Enabled = true;
					m_isIdle = true;
					m_duplicator.CancelDup();
				}
			}
			else
			{
				if (MessageBox.Show("Huh? Are you sure you want to cancel " +
					" the VM duplication?", "Cancellation asked",
					MessageBoxButtons.YesNo) == DialogResult.Yes)
				{
					dupWorker.CancelAsync();
					dupBtn.Enabled = false;
				}
			}
		}

		private bool ValidateParams()
		{
			if (newVmName.Text.Length * newVmcDir.Text.Length * newVhdDir.Text.Length == 0)
			{
				MessageBox.Show("Please fill all fields of the form");
				return false;
			}
			if (!Directory.Exists(newVmcDir.Text))
			{
				if (MessageBox.Show("New vmc dir does not exist. Create it?", "Invalid dir",
					MessageBoxButtons.OKCancel) == DialogResult.Cancel)
					return false;
				try
				{
					Directory.CreateDirectory(newVmcDir.Text);
				}
				catch (Exception ex)
				{
					MessageBox.Show("Dir could not be created: " + ex.Message +
						"\nPlease choose another one.");
					return false;
				}
			}
			if (!Directory.Exists(newVhdDir.Text))
			{
				if (MessageBox.Show("New vhd dir does not exist. Create it?", "Invalid dir",
					MessageBoxButtons.OKCancel) == DialogResult.Cancel)
					return false;
				try
				{
					Directory.CreateDirectory(newVhdDir.Text);
				}
				catch (Exception ex)
				{
					MessageBox.Show("Dir could not be created: " + ex.Message +
						"\nPlease choose another one.");
					return false;
				}
			}
			return true;
		}

		private string FullDir(string dir)
		{
			if (dir.EndsWith("\\"))
				return dir;
			return dir + "\\";
		}

		private string GetFileDir(string file)
		{
			int dirEnd = file.LastIndexOf('\\');
			return file.Substring(0, dirEnd + 1);
		}

		// http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

		private void dupWorker_DoWork(object sender, DoWorkEventArgs e)
		{
			// Get the BackgroundWorker that raised this event.
			BackgroundWorker worker = sender as BackgroundWorker;

			// Assign the result of the computation
			// to the Result property of the DoWorkEventArgs
			// object. This is will be available to the 
			// RunWorkerCompleted eventhandler.
			VmInfo trgVm = e.Argument as VmInfo;
			m_duplicator = new Duplicator(worker, e);
			e.Result = m_duplicator.Duplicate(m_srcVm, trgVm);
		}

		private void dupWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			dupProgress.Value = e.ProgressPercentage;
		}

		private void dupWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			// First, handle the case where an exception was thrown.
			if (e.Error != null)
			{
				m_duplicator.CancelDup();	// includes cleanup
				MessageBox.Show("Errr... the duplication has failed due to " +
					"unexpected circumstances.\n\nThe gory details:\n" +
					e.Error.Message);
			}
			else if (e.Cancelled)
			{
				// Next, handle the case where the user canceled 
				// the operation.
				// Note that due to a race condition in 
				// the DoWork event handler, the Cancelled
				// flag may not have been set, even though
				// CancelAsync was called.
				m_duplicator.CancelDup();	// includes cleanup
			}
			else
			{
				// Finally, handle the case where the operation 
				// succeeded.
				m_newVm = newVmName.Text;
				m_isIdle = true;
				Close();
				return;
			}
			// if we got here, dup either failed or was cancelled.
			// either way, the dialog should allow another dup.
			dupBtn.Text = "Duplicate!";
			dupBtn.Enabled = true;
			m_isIdle = true;
		}

		private void DuplicateForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (!m_isIdle)
				e.Cancel = true;
		}
	}
}
